/*
 * ModelCC, distributed under ModelCC Shared Software License, www.modelcc.org
 */

package org.modelcc.language.syntax;

import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.modelcc.IModel;
import org.modelcc.language.metamodel.LanguageModel;

/**
 * Parser metadata.
 * 
 * @author Luis Quesada (lquesada@modelcc.org) & Fernando Berzal (fberzal@gmail.com)
 */
public final class ParserMetadata implements Serializable 
{
	/**
	 * Language model.
	 */
	private LanguageModel model;
	
    /**
     * Object map.
     */ 
    private Map<Object,ObjectWrapper> map;

    /**
     * Key map.
     */
    private Map<Class,Map<ObjectWrapper,Object>> keys;
   
    /**
     * Lazy references.
     */
    private Set<Symbol> lazyReferences;
    
    /**
     * Use map
     */
    private Map<Symbol,Set<Symbol>> used;
    
    /**
     * Constructor.
     */
    public ParserMetadata (LanguageModel model) 
    {
    	this.model = model;
        keys = new HashMap<Class,Map<ObjectWrapper,Object>>();
        map = new HashMap<Object,ObjectWrapper>();
        lazyReferences = new HashSet<Symbol>();
        used = null;
    }

    // Getters
    
    public LanguageModel getModel ()
    {
    	return model;
    }
    
    public void add (IModel element)
    {
    	Map<ObjectWrapper,Object> idmap = getKeys(element.getClass());
    	
        ObjectWrapper wrapper = ObjectWrapper.createKeyWrapper(element, getModel(), getMap());
        
        if (!idmap.containsKey(wrapper)) {
        	idmap.put(wrapper, element);
        	map.put(element, wrapper);
        }
    }
    
    public void addReference (Object obj, Symbol t)
    {
		Map<ObjectWrapper,Object> idmap = getKeys(obj.getClass());
		
		ObjectWrapper kw = ObjectWrapper.createKeyWrapper(obj, getModel(), getMap());

		if (idmap.containsKey(kw)) {
		    t.setUserData(idmap.get(kw));
		} else {
		    getLazyReferences().add(t);
		}
    }
    
    public Map<Class,Map<ObjectWrapper,Object>> getKeys() 
    {
        return keys;
    }

    public Map<ObjectWrapper,Object> getKeys (Class c) 
    {
        Map<ObjectWrapper,Object> idmap = keys.get(c);

        if (idmap == null) {
            idmap = new HashMap<ObjectWrapper,Object>();
            keys.put(c,idmap);
        }
    	
        return idmap;
    }
    
    
    public Map<Object,ObjectWrapper> getMap() 
    {
        return map;
    }

    public Set<Symbol> getLazyReferences() 
    {
        return lazyReferences;
    }    
    
    // Use map

    public Map<Symbol,Set<Symbol>> getUsed ()
    {
    	return used;
    }
    
    public void setUsed (Map<Symbol,Set<Symbol>> used)
    {
    	this.used = used;
    }
}